package org.kisekiproject.evaluator {
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.utils.Dictionary;
	
	import org.kisekiproject.evaluator.events.VariableChangeEvent;

	/**
	 * A variable store that can use expressions as variables.
	 */
	public class VariableExpressionStore extends EventDispatcher implements IVariableNamespace {

		private var _constants:Dictionary;
		private var _expressions:Dictionary;
		private var _nameByExpression:Dictionary;

		/**
		 * Constructor.
		 */
		public function VariableExpressionStore() {
			_constants=new Dictionary();
			_expressions=new Dictionary();
			_nameByExpression=new Dictionary();
		}

		/**
		 * Set variable.
		 */
		public function setVariable(name:String, value:Object):void {
			delete _constants[name];
			delete _expressions[name];

			_constants[name]=value;
			dispatchEvent(new VariableChangeEvent(VariableChangeEvent.VARIABLE_CHANGE,name));
		}

		/**
		 * Set an expression to use as variable.
		 */
		public function setVariableExpression(name:String, expression:IExpression):void {
			delete _constants[name];
			delete _expressions[name];

			_expressions[name]=expression;
			_nameByExpression[expression]=name;
			expression.addEventListener(Event.CHANGE,onExpressionChange);
			dispatchEvent(new VariableChangeEvent(VariableChangeEvent.VARIABLE_CHANGE,name));
		}
		
		private function onExpressionChange(event:Event):void {
			var exp:IExpression=IExpression(event.target);
			var name:String=_nameByExpression[exp];
	
			dispatchEvent(new VariableChangeEvent(VariableChangeEvent.VARIABLE_CHANGE,name));
		}
		
		/**
		 * Get variable value.
		 */
		public function getVariable(name:String):Object {
			trace("getting variable: "+name);
			if (_constants[name]!==undefined)
				return _constants[name];

			if (_expressions[name])
				return IExpression(_expressions[name]).value;

			throw new Error("Variable not defined: "+name);
		}

		/**
		 * Notify variable change.
		 */
		public function notifyVariableChange(name:String):void {
			dispatchEvent(new VariableChangeEvent(VariableChangeEvent.VARIABLE_CHANGE,name));
		}
	}
}